package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.domain.entity.SysUser;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.framework.config.properties.HuaWeiIotConfigProperties;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IDeviceService;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.ProductVo;
import com.zzyl.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备管理Service业务层处理
 *
 * @author zzyl
 * @date 2025-10-23
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {
    @Autowired
    private DeviceMapper deviceMapper;

    /**
     * 查询设备管理
     *
     * @param id 设备管理主键
     * @return 设备管理
     */
    @Override
    public Device selectDeviceById(Long id) {
        return getById(id);
    }

    /**
     * 查询设备管理列表
     *
     * @param device 设备管理
     * @return 设备管理
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备管理
     *
     * @param device 设备管理
     * @return 结果
     */
    @Override
    public int insertDevice(Device device) {
        return save(device) ? 1 : 0;
    }

    /**
     * 修改设备管理
     *
     * @param dto 设备管理
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDevice(DeviceDto dto) {
        Device device = this.lambdaQuery()
                .eq(Device::getId, dto.getId())
                .one();
        if (device == null) {
            throw new BaseException("要修改的设备不存在");
        }

        boolean result = this.lambdaUpdate()
                .set(Device::getDeviceName, dto.getDeviceName())
                .set(Device::getNickname, dto.getNickname())
                .eq(Device::getId, dto.getId())
                .update();

        UpdateDeviceRequest updateDeviceRequest = new UpdateDeviceRequest();
        updateDeviceRequest.withDeviceId(device.getIotId());
        UpdateDevice updateDevice = new UpdateDevice();
        updateDevice.setDeviceName(dto.getDeviceName());
        updateDevice.setDescription(dto.getNickname());
        updateDeviceRequest.setBody(updateDevice);
        UpdateDeviceResponse response = client.updateDevice(updateDeviceRequest);
        if (response.getHttpStatusCode() != HttpStatus.HTTP_OK){
            throw new BaseException("更新失败");
        }

        return result ? 1:0;
    }

    /**
     * 批量删除设备管理
     *
     * @param ids 需要删除的设备管理主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除设备管理信息
     *
     * @param id 设备管理主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id) {
        return removeById(id) ? 1 : 0;
    }


    @Autowired
    private IoTDAClient client;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 物联网平台同步产品列表
     */
    @Override
    public void syncProductList() {
        try {
            //从IoT平台获取产品列表
            ListProductsResponse response = client.listProducts(new ListProductsRequest());
            //根据响应数据判断是否获取成功
            if (response.getHttpStatusCode() != HttpStatus.HTTP_OK) {
                throw new BaseException("同步产品失败");
            }
            //从响应对象中获取产品列表
            List<ProductSummary> productSummaryList = response.getProducts();
            //将产品列表转换为JSON字符串
            String jsonStr = JSONUtil.toJsonStr(productSummaryList);
            //将字符串存储到Redis中
            redisTemplate.opsForValue().set(CacheConstants.IOT_PRODUCT_LIST_KEY, jsonStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 获取产品列表
     *
     * @return 产品列表
     */
    @Override
    @Transactional
    public List<ProductVo> allProduct() {
        //从Redis中获取产品列表的JSON字符串
        String JsonStr = redisTemplate.opsForValue().get(CacheConstants.IOT_PRODUCT_LIST_KEY);
        //将JSON字符串转换为集合
        List<ProductSummary> productSummaries = JSONUtil.toList(JsonStr, ProductSummary.class);
        //将集合的类型转换为VO
        List<ProductVo> productVoList = productSummaries.stream()
                .map(x ->
                        ProductVo.builder()
                                .productKey(x.getProductId())
                                .productName(x.getName())
                                .build()).collect(Collectors.toList());
        //将得到的集合返回
        return productVoList;
    }

    /**
     * 注册设备
     *
     * @param dto
     */
    @Override
    @Transactional
    public void register(DeviceDto dto) {
        //1.判断设备名是否重复
        Long countByDeviceName = this.lambdaQuery()
                .eq(Device::getDeviceName, dto.getDeviceName())
                .count();
        if (countByDeviceName > 0){
            throw new BaseException("设备名称重复");
        }
        //2.判断设备标识是否重复
        String nodeId = IdUtil.getSnowflakeNextIdStr();
        //3。判断同一位置是否绑定了相同的产品
        Long countByLocationAndDeviceName = this.lambdaQuery()
                .eq(Device::getLocationType, dto.getLocationType())
                .eq(Device::getPhysicalLocationType, dto.getPhysicalLocationType())
                .eq(Device::getDeviceName, dto.getDeviceName())
                .eq(Device::getProductKey,dto.getProductKey())
                .count();
        if (countByLocationAndDeviceName > 0){
            throw new BaseException("该位置已绑定了相同的产品");
        }
        //4.注册设备
        AddDeviceRequest addDeviceRequest = new AddDeviceRequest();
        AddDevice addDevice = new AddDevice();
        //设备唯一标识
        addDevice.setNodeId(nodeId);
        //设备英文名
        addDevice.setDeviceName(dto.getDeviceName());
        //设备中文名
        addDevice.setDescription(dto.getNickname());
        //产品id
        String productId = dto.getProductKey();
        addDevice.setProductId(productId);
        //认证信息
        AuthInfo authInfo = new AuthInfo();

        String secret = IdUtil.fastSimpleUUID();
        authInfo.setSecret(secret);
        addDevice.setAuthInfo(authInfo);

        addDeviceRequest.setBody(addDevice);

        try {
            AddDeviceResponse response = client.addDevice(addDeviceRequest);
            if (response.getHttpStatusCode() != HttpStatus.HTTP_CREATED){
                throw new BaseException("设备注册失败");
            }
            //本地保存设备
            String iotId = response.getDeviceId();
            Device device = BeanUtil.toBean(dto, Device.class);
            device.setIotId(iotId);
            device.setNodeId(nodeId);
            device.setSecret(secret);
            String productName = getProductName(productId);
            device.setProductName(productName);
            device.setHaveEntranceGuard(dto.getNickname().contains("门禁")?1:0);
            this.save(device);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("设备注册失败");
        }
    }

    private String getProductName(String productId) {
        String jsonStr = redisTemplate.opsForValue().get(CacheConstants.IOT_PRODUCT_LIST_KEY);
        if (StrUtil.isBlank(jsonStr)) {
            return null;
        }
        List<ProductSummary> productSummaryList = JSONUtil.toList(jsonStr, ProductSummary.class);

        ProductSummary productSummary = productSummaryList.stream().filter(x -> x.getProductId().equals(productId)).findFirst().get();
        return productSummary.getName();
    }


    @Autowired
    private HuaWeiIotConfigProperties huaWeiIotConfigProperties;

    @Autowired
    private ISysUserService sysUserService;
    /**
     * 查询设备详细数据
     *
     */
    @Override
    @Transactional
    public DeviceDetailVo queryDeviceDetail(String iotId, String productKey) {
        Device device = this.lambdaQuery()
                .eq(Device::getIotId, iotId)
                .eq(Device::getProductKey, productKey)
                .one();
        if (device == null){
            throw new BaseException("设备不存在");
        }
        DeviceDetailVo detailVo = BeanUtil.toBean(device, DeviceDetailVo.class);
        //创建时间
        detailVo.setGmtCreate(device.getCreateTime());
        //创建人
        Long creatBy = Long.valueOf(device.getCreateBy());
        SysUser sysUser = sysUserService.selectUserById(creatBy);
        detailVo.setCreator(sysUser.getUserName());
        //设备密钥
        detailVo.setDeviceSecret(device.getSecret());
        //地域
        String regionId = huaWeiIotConfigProperties.getRegionId();
        detailVo.setRegion(regionId);
        try {
            ShowDeviceRequest deviceRequest = new ShowDeviceRequest();
            deviceRequest.withDeviceId(iotId);
            ShowDeviceResponse response = client.showDevice(deviceRequest);
            if (response.getHttpStatusCode() != HttpStatus.HTTP_OK){
                throw new BaseException("IoT平台查询失败");
            }
            //设备状态
            detailVo.setDeviceStatus(response.getStatus());
            //固定版本
            detailVo.setFirmwareVersion(response.getFwVersion());
            //激活时间
            String activeTime = response.getActiveTime();
            //格式化时间 设备激活时间原格式：yyyy-MM-dd'T'HH:mm:ss.SSS'Z' ，如2015-12-12T12:12:122Z。
            if (StrUtil.isNotBlank(activeTime)){
                LocalDateTime localDateTime = OffsetDateTime.parse(activeTime)
                        .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                        .toLocalDateTime();
                detailVo.setGmtActive(localDateTime);
            }
            return detailVo;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("IoT平台查询失败");
        }
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     *
     * @param productKey
     */
    @Override
    public JSONObject queryProductModelInfo(String productKey) {
        //创建请求对象
        ShowProductRequest showProductRequest = new ShowProductRequest();
        //添加请求体中的参数
        showProductRequest.withProductId(productKey);
        try {
            //发送请求获取产品信息
            ShowProductResponse response = client.showProduct(showProductRequest);
            //检验响应状态码是否是200，
            if (response.getHttpStatusCode() != HttpStatus.HTTP_OK){
                throw new BaseException("查询IoT平台失败");
            }
            //获取响应数据中所需的数据
            List<ServiceCapability> serviceCapabilities = response.getServiceCapabilities();
            //将数据转换为JSONObject格式，使数据名的下划线形式转换为驼峰形式
            JSONObject jsonObject = JSONUtil.parseObj(serviceCapabilities.get(0));
            return jsonObject;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("查询IoT平台失败");
        }
    }

    /**
     * 删除设备
     *
     * @param iotId
     * @param productKey
     * @return
     */
    @Override
    @Transactional
    public int deleteDeviceByIds(String iotId, String productKey) {


        //1. 删除数据库的设备
        boolean remove = this.lambdaUpdate()
                .eq(Device::getIotId, iotId)
                .eq(Device::getProductKey, productKey)
                .remove();
        //2 删除Iot平台上的设备
        DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
        deleteDeviceRequest.withDeviceId(iotId);
        DeleteDeviceResponse deleteDeviceResponse = client.deleteDevice(deleteDeviceRequest);
        if (deleteDeviceResponse.getHttpStatusCode() != HttpStatus.HTTP_NO_CONTENT){
            throw new BaseException("IoT平台删除失败");
        }
        return remove?1:0;
    }

    /**
     * 询指定设备的物模型运行状态
     */
    @Override
    public Map<String, Object> queryDevicePropertyStatus(String deviceName, String productKey) {
        Device device = this.lambdaQuery()
                .eq(Device::getDeviceName, deviceName)
                .eq(Device::getProductKey, productKey)
                .one();
        ShowDeviceShadowRequest showDeviceShadowRequest = new ShowDeviceShadowRequest();
        showDeviceShadowRequest.withDeviceId(device.getIotId());
        try {
            ShowDeviceShadowResponse response = client.showDeviceShadow(showDeviceShadowRequest);
            if (response.getHttpStatusCode() != HttpStatus.HTTP_OK){
                throw new BaseException("IoT平台查询失败");
            }
            List<DeviceShadowData> shadowDataList = response.getShadow();
            if (CollUtil.isEmpty(shadowDataList)){
                return Collections.emptyMap();
            }
            DeviceShadowProperties reported = shadowDataList.get(0).getReported();
            //格式化时间，原格式为：20151212T121212Z
            String eventTime = reported.getEventTime();
            LocalDateTime dateTime = OffsetDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX"))
                    .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime();
            JSONObject jsonObject = JSONUtil.parseObj(reported.getProperties());
            List<Map<String,Object>> propertyStatusInfoList = new ArrayList<>();
            jsonObject.forEach((k,v) ->{
                String propertyName = k;
                Object propertyValue = v;

                Map<String,Object> propertyMap = new HashMap<>();
                propertyMap.put("identifier",propertyName);
                propertyMap.put("value",propertyValue);
                propertyMap.put("time",dateTime);
                propertyStatusInfoList.add(propertyMap);
            });

            Map<String,Object> propertyStatusInfoMap = new HashMap<>();
            propertyStatusInfoMap.put("propertyStatusInfo",propertyStatusInfoList);

            Map<String,Object> resultMap = new HashMap<>();
            resultMap.put("list",propertyStatusInfoMap);

            return resultMap;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("IoT平台查询失败");
        }


    }
}
